#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/delay.h>

#define CNAME "myap3216"

struct i2c_client *ap3216_client;
struct cdev *cdev;
struct class *cls;
struct device *dev;
wait_queue_head_t wq_head;
unsigned int condition = 0;
struct work_struct work;
int major = 0;
int minor = 0;

int i2c_write_reg(unsigned char reg, unsigned char data)
{
    int ret;
    unsigned char w_buf[] = {reg, data};
    // 1.封装i2c_msg结构体
    struct i2c_msg w_msg[] = {
        [0] = {
            .addr = ap3216_client->addr,
            .flags = 0,
            .len = 2,
            .buf = w_buf,
        },
    };
    // 2.发送消息
    ret = i2c_transfer(ap3216_client->adapter, w_msg, 1);
    if (ret != 1)
    {
        printk("i2c_transfer error\n");
        return -EAGAIN;
    }
    return 0;
}
// 读操作
int i2c_read_reg(unsigned char reg)
{
    int ret;
    unsigned char r_buf[] = {reg};
    unsigned char data;
    // 1.封装i2c_msg结构体
    struct i2c_msg r_msg[] = {
        [0] = {
            .addr = ap3216_client->addr,
            .flags = 0,
            .len = 1,
            .buf = r_buf,
        },
        [1] = {
            .addr = ap3216_client->addr,
            .flags = I2C_M_RD,
            .len = 2,
            .buf = &data,
        },
    };
    // 2.发送消息
    ret = i2c_transfer(ap3216_client->adapter, r_msg, 2);
    if (ret != 2)
    {
        printk("i2c_transfer error\n");
        return -EAGAIN;
    }
    return data;
}

// 工作队列处理函数
void ap3216_work_handler(struct work_struct *work)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    // 1.唤醒休眠
    condition = 1;
    wake_up_interruptible(&wq_head);
    // 2.清除中断状态标志位
    i2c_write_reg(0x2, 0x1);
    i2c_write_reg(0x1, 0x3);
}

irqreturn_t ap3216_irq_handler(int irqno, void *dev_id)
{
    schedule_work(&work); // 调用工作队列底半部
    return IRQ_HANDLED;
}

int ap3216_open(struct inode *inode, struct file *file)
{
    printk("%s,%s,%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t ap3216_read(struct file *file, char __user *user, size_t size, loff_t *loffs)
{
    int ret;
    int ap3216val[3] = {0};
    int data_l = 0;
    int data_h = 0;
    printk("%s,%s,%d\n", __FILE__, __func__, __LINE__);

    if (size > 12)
        size = 12;

    // 读取人体红外
    data_l = i2c_read_reg(0x0a);
    data_h = i2c_read_reg(0x0b);
    if (data_l & 0x80)
        ap3216val[0] = 0;
    else
        ap3216val[0] = (data_h << 2) | (data_l & 0x03);

    // 环境光
    data_l = i2c_read_reg(0x0c);
    data_h = i2c_read_reg(0x0d);
    ap3216val[1] = (data_h << 8) | (data_l);

    // 接近
    data_l = i2c_read_reg(0x0e);
    data_h = i2c_read_reg(0x0f);
    if (data_l & 0x40)
        ap3216val[2] = 0;
    else
        ap3216val[2] = ((data_h & 0x3f) << 4) | (data_l & 0x0f);

    ret = copy_to_user(user, ap3216val, size);
    if (ret)
    {
        printk("%s,%s,%d\n", __FILE__, __func__, __LINE__);
        printk(KERN_ERR "copy_to_user error!\n");
        return -EFAULT;
    }

    // 5.条件设置为0
    condition = 0;
    return size;
}
int ap3216_close(struct inode *inode, struct file *file)
{
    printk("%s,%s,%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

const struct file_operations fops = {
    .open = ap3216_open,
    .read = ap3216_read,
    .release = ap3216_close,
};

int ap3216_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret;
    dev_t devno;

    printk("%s,%s,%d\n", __FILE__, __func__, __LINE__);
    ap3216_client = client;

    // 初始化
    i2c_write_reg(0x00, 0x04);
    mdelay(100); // 延时100ms
    // 1.2设置ALS，PS，IR的功能
    i2c_write_reg(0x00, 0x03);

    cdev = cdev_alloc();
    if (NULL == cdev)
    {
        printk(KERN_ERR "cdev_alloc error");
        ret = -ENOMEM;
        goto err1;
    }

    cdev_init(cdev, &fops);

    ret = alloc_chrdev_region(&devno, 0, 1, CNAME);
    if (ret)
    {
        printk(KERN_ERR "register_chrdev_region error");
        goto err2;
    }
    major = MAJOR(devno);
    minor = MINOR(devno);

    ret = cdev_add(cdev, MKDEV(major, minor), 1);
    if (ret)
    {
        printk(KERN_ERR "cdev_add error");
        goto err3;
    }

    cls = class_create(THIS_MODULE, CNAME);
    if (IS_ERR(cls))
    {
        printk(KERN_ERR "class_create error");
        ret = PTR_ERR(cls);
        goto err4;
    }

    dev = device_create(cls, NULL, MKDEV(major, minor), NULL, CNAME);
    if (IS_ERR(dev))
    {
        printk(KERN_ERR "device_create error");
        ret = PTR_ERR(dev);
        goto err5;
    }

    // 初始化工作队列
    INIT_WORK(&work, ap3216_work_handler);
    // 3.注册中断  client->irq
    ret = request_irq(client->irq, ap3216_irq_handler,
                      IRQF_TRIGGER_FALLING, "ap3216", NULL);
    if (ret < 0)
    {
        printk(KERN_ERR "device_create error");
        ret = EINVAL;
        goto err6;
    }

    init_waitqueue_head(&wq_head);
    return 0;

err6:
    device_destroy(cls, MKDEV(major, minor));

err5:
    class_destroy(cls);

err4:
    cdev_del(cdev);

err3:
    unregister_chrdev_region(MKDEV(major, minor), 1);

err2:
    kfree(cdev);

err1:
    return ret;
}
int ap3216_remove(struct i2c_client *client)
{
    printk("%s,%s,%d\n", __FILE__, __func__, __LINE__);

    cancel_work_sync(&work);
    free_irq(ap3216_client->irq, NULL);
    device_destroy(cls, MKDEV(major, minor));
    class_destroy(cls);
    cdev_del(cdev);
    unregister_chrdev_region(MKDEV(major, minor), 1);
    kfree(cdev);
    i2c_write_reg(0x00, 0x00); // power down

    return 0;
}

struct of_device_id oftable[] = {
    {
        .compatible = "hqyj,ap3216",
    },
    {}};

struct i2c_driver ap3216_driver = {
    .probe = ap3216_probe,
    .remove = ap3216_remove,
    .driver = {
        .name = "ap3216",
        .of_match_table = oftable,
    },
};

module_i2c_driver(ap3216_driver);
MODULE_LICENSE("GPL");
